page.tsx 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. import { notFound } from "next/navigation";
  2. import { Suspense } from "react";
  3. // import clsx from "clsx";
  4. // import type { ProductReviewList } from "@/types/products/productDetail";
  5. // import { getProductReviews } from "@utils/hooks/getProductReviews";
  6. import { restApiFetch } from "@utils/bagisto/index";
  7. import {
  8. ProductDetailSkeleton,
  9. RelatedProductSkeleton,
  10. } from "@/components/common/skeleton/ProductSkeleton";
  11. import { BASE_SCHEMA_URL, PRODUCT_TYPE } from "@/utils/constants";
  12. import { GET_PRODUCT_BY_URL_KEY } from "@/graphql";
  13. import { cachedProductRequest } from "@/utils/hooks/useCache";
  14. import {
  15. ProductOption,
  16. SingleProductResponse,
  17. ProductMediaType,
  18. } from "@components/catalog/type";
  19. import { RelatedProductsSection } from "@components/catalog/product/RelatedProductsSection";
  20. import { HeroCarouselShimmer } from "@components/common/slider";
  21. import { ProductMedia } from "@/app/(public)/product/_components/ProductMedia";
  22. import { ProductInformation } from "@/app/(public)/product/_components/ProductInformation";
  23. import { ProductShortDescription } from "@/app/(public)/product/_components/ProductShortDescription";
  24. import { ProductDetail } from "@/app/(public)/product/_components/ProductDetail";
  25. import SwitchButton from "../_components/SwitchButton";
  26. import ShopServicePanel from "../_components/ShopServicePanel";
  27. import Recommend from "../_components/youmaylike/Recommend"
  28. import { formatFlexibleVariants } from "@/utils/variantTools";
  29. // export const dynamic = 'auto'
  30. // // 'auto' | 'force-dynamic' | 'error' | 'force-static'
  31. export const dynamic = "force-dynamic";
  32. async function getSingleProduct(urlKey: string) {
  33. try {
  34. const { data: dataById } =
  35. await cachedProductRequest<SingleProductResponse>(
  36. // urlKey, // 产品名称
  37. GET_PRODUCT_BY_URL_KEY, // gql查询语句
  38. { urlKey: urlKey },
  39. );
  40. const product = dataById?.product || null;
  41. return product;
  42. } catch (error) {
  43. if (error instanceof Error) {
  44. console.error("Error fetching product:", {
  45. message: error.message,
  46. urlKey,
  47. graphQLErrors: (error as unknown as Record<string, unknown>)
  48. .graphQLErrors,
  49. });
  50. }
  51. return null;
  52. }
  53. }
  54. //动态路由中的参数 -- params
  55. export default async function ProductPage({
  56. params,
  57. }: {
  58. params: Promise<{ urlProduct: string[] }>;
  59. searchParams: Promise<{ type: string }>;
  60. }) {
  61. const { urlProduct } = await params;
  62. const fullPath = urlProduct.join("/");
  63. const product = await getSingleProduct(fullPath);
  64. if (!product) return notFound();
  65. // const allReviews: ProductReviewList = await getProductReviews(
  66. // String(product._id),
  67. // );
  68. // 3792
  69. const res = await restApiFetch({
  70. api: `/shop/products/${3792}/reviews?page=1&per_page=10&has_images=0&sort=all`,
  71. method: "GET",
  72. });
  73. const allReviews = res?.body?.data;
  74. console.log("res----------------------",allReviews);
  75. const questionTotal = 73;
  76. // const imageUrl = getImageUrl(product?.baseImageUrl, baseUrl, NOT_IMAGE);
  77. // JSON-LD数据格式,便于搜索引擎识别页面信息,利于seo
  78. const productJsonLd = {
  79. "@context": BASE_SCHEMA_URL,
  80. "@type": PRODUCT_TYPE,
  81. name: product?.name,
  82. description: product?.description,
  83. sku: product?.sku,
  84. };
  85. const mediaImgs = (product?.images?.edges ?? []).map(
  86. (edge: { node: ProductMediaType }) => {
  87. return edge.node;
  88. },
  89. );
  90. const productOptions: ProductOption[] = product?.productOptions
  91. ? JSON.parse(product?.productOptions)
  92. : [];
  93. const flexibleVariants = formatFlexibleVariants(product?.flexibleVariants);
  94. // const reviews = Array.isArray(product?.reviews?.edges)
  95. // ? product?.reviews.edges.map((e) => e.node)
  96. // : [];
  97. // const VariantImages = isArray(product?.variants?.edges)
  98. // ? product?.variants.edges.map(
  99. // (edge: { node: ProductVariantNode }) => edge.node,
  100. // )
  101. // : [];
  102. return (
  103. <>
  104. <script //SEO
  105. dangerouslySetInnerHTML={{
  106. __html: JSON.stringify(productJsonLd),
  107. }}
  108. type="application/ld+json"
  109. />
  110. <div className="w-full">
  111. <Suspense fallback={<HeroCarouselShimmer />}>
  112. <ProductMedia mediaData={mediaImgs} />
  113. </Suspense>
  114. </div>
  115. <div className="">
  116. <Suspense fallback={<ProductDetailSkeleton />}>
  117. <ProductInformation
  118. key={product._id}
  119. productId={product._id}
  120. name={product?.name || ""}
  121. productOptions={productOptions}
  122. flexibleVariants={flexibleVariants}
  123. isSaleable={product.isSaleable}
  124. />
  125. <ShopServicePanel />
  126. <ProductShortDescription
  127. shortDescription={product.shortDescription || ""}
  128. />
  129. <SwitchButton
  130. productId={"3792"} //|| String(product._id)
  131. reviewList={allReviews}
  132. reviewTotal={allReviews.length}
  133. questionTotal={questionTotal}
  134. questionList={["aaa"]}
  135. />
  136. <ProductDetail detail={product.description || ""} />
  137. {/* <ProductReviewSection reviews={allReviews} productId={String(product._id)} /> */}
  138. </Suspense>
  139. <Recommend/>
  140. </div>
  141. <Suspense fallback={<RelatedProductSkeleton />}>
  142. <RelatedProductsSection fullPath={fullPath} />
  143. </Suspense>
  144. </>
  145. );
  146. }